#include "Character.h"

using namespace std;
using namespace Ogre;
using namespace BtOgre;



    /**
    * Constructor
    */
    Character::Character(SceneManager* sceneMgr) : GameObject(sceneMgr)
    {
        // Load the mesh
        mEntity = sceneMgr->createEntity(getName(), "Zombie.mesh");
//        mEntity = sceneMgr->createEntity(getName(), "Meka.mesh");
        mEntity->setCastShadows(true);
		mEntity->setUserAny(Any(static_cast<BaseGameObject*>(this)));

		// Attach to node
        mNode->attachObject(mEntity);

        // Grab a skeleton ptr
        mSkeleton = mEntity->getSkeleton();
		mEntity->setDisplaySkeleton(true);

//	   Ogre::Skeleton::BoneIterator it = mSkeleton->getBoneIterator();
//	   while(it.hasMoreElements())
//		  it.getNext()->setManuallyControlled(true);

        mJumping = false;
        mAnimSpeed = 1.0f;
        mDirection = Vector3::UNIT_Z;
        mTranslateVector = Vector3::ZERO;
        mCurrentSpeed = 0.0f;

    //    btVector3 inertia;

    //    mRayQuery = sceneMgr->createRayQuery(Ray());

    //    btTransform startTransform;
    //    startTransform.setIdentity ();
    //    startTransform.setOrigin (BtOgre::Convert::toBullet(mNode->getPosition()));

    //    btScalar characterHeight = 3.25f;
    //    btScalar characterWidth  = 2.0f;

    //    capsule = new btCapsuleShape(characterWidth,characterHeight);

    //    m_ghostObject = new btPairCachingGhostObject();
    //    m_ghostObject->setWorldTransform (startTransform);
    //    m_ghostObject->setCollisionShape (capsule);

    //    btScalar stepHeight = 0.35f;
    //    mCharacterController = new btKinematicCharacterController (m_ghostObject, capsule, stepHeight);
    }

    /**
    * Destructor
    */
    Character::~Character()
    {
//        if(mRagDoll)
//            delete mRagDoll;

    }


    /**
    * onGround
    * @return true if player's on ground, false otherwise
    */
    bool Character::onGround ()
    {
        if (mJumping) return false;

        btVector3 rayFrom = BtOgre::Convert::toBullet(mNode->getPosition());
        btVector3 rayTo = BtOgre::Convert::toBullet(mNode->getPosition() + Vector3::NEGATIVE_UNIT_Y*1000);
        btCollisionWorld::ClosestRayResultCallback resultCallback(rayFrom,rayTo);

        if (resultCallback.hasHit())
        {
            if (resultCallback.m_hitPointWorld[1] == mNode->getPosition().y)
                return true;
        }

        return false;
    }



    /**
    * Inject key presses
    */
    void Character::onKeyDown(const OIS::KeyEvent& e)
    {
        Real mMove = 0.01f;
        switch (e.key)
        {
        case OIS::KC_W:
            mTranslateVector.z = mMove;
            if (mJumping) break;
            getAnimState("Walk")->setEnabled(false);
            getAnimState("Walk")->setWeight(0);
            getAnimState("Run")->setEnabled(true);
            getAnimState("Run")->setWeight(1);
            break;
        case OIS::KC_S:
            mTranslateVector.z = -mMove / 2;
            if (mJumping) break;
            getAnimState("Run")->setEnabled(false);
            getAnimState("Walk")->setEnabled(true);
            getAnimState("Walk")->setWeight(1);
            break;
        case OIS::KC_A:
            mTranslateVector.x = mMove;
            if (mJumping) break;
            getAnimState("Strafe")->setEnabled(true);
            getAnimState("Strafe")->setWeight(1);
            break;
        case OIS::KC_D:
            mTranslateVector.x = -mMove;
            if (mJumping) break;
            getAnimState("Strafe")->setEnabled(true);
            getAnimState("Strafe")->setWeight(1);
            break;

        case OIS::KC_SPACE:
            if (mJumping) break;
            getAnimState("Walk")->setWeight(0);
            getAnimState("Run")->setWeight(0);

            getAnimState("Jump")->setTimePosition(0);
            getAnimState("Jump")->setEnabled(true);
            getAnimState("Jump")->setWeight(1);
            getAnimState("Jump")->setLoop(false);
            mJumping = true;
            break;

        default:
            break;

        }
    }

    /**
    * Inject key releases
    */
    void Character::onKeyUp(const OIS::KeyEvent& e)
    {
        switch (e.key)
        {
        case OIS::KC_W:
            mTranslateVector.z = 0;
            break;
        case OIS::KC_S:
            mTranslateVector.z = 0;
            break;
        case OIS::KC_A:
            getAnimState("Strafe")->setEnabled(false);
            getAnimState("Strafe")->setWeight(0);
            mTranslateVector.x = 0;
            break;
        case OIS::KC_D:
            getAnimState("Strafe")->setEnabled(false);
            getAnimState("Strafe")->setWeight(0);
            mTranslateVector.x = 0;
            break;

        case OIS::KC_SPACE:
            break;

        default:
            break;
        }
    }


    /**
    * Update character based on time
    * @return true to continue rendering
    */
    bool Character::frameRenderingQueued(const FrameEvent& evt)
    {
/*
        Real dt = evt.timeSinceLastFrame;

        Real M = 1.0f;

        AnimationStateSet* ass = mEntity->getAllAnimationStates();
        AnimationStateIterator iter = ass->getAnimationStateIterator();
        AnimationState *as;

        // add time to all animations
        while (iter.hasMoreElements())
        {
            as = iter.getNext();
            String name = as->getAnimationName();

            if (name=="Run")
                as->addTime(M*mCurrentSpeed*dt);
            else
                if (name=="Walk" && mTranslateVector.z < 0)
                    as->addTime(-2*M*mCurrentSpeed*dt);

            if (name=="Jump")
                as->addTime(.5*mAnimSpeed*dt);
            else
                as->addTime(mAnimSpeed*dt);
        }

        Real J = 0.0275f;
        if (mJumping)
        {
            if (getAnimState("Jump")->getTimePosition() > 0.33)
                mTranslateVector.y = J ;

            if (getAnimState("Jump")->getTimePosition() > 0.50)
                mJumping = false;
        }
        else
        {
            mTranslateVector.y = 0;
        }


        if (mTranslateVector == Ogre::Vector3::ZERO)
        {
            mCurrentSpeed -= 0.33f*dt;
            getAnimState("Idle")->setEnabled(true);
            getAnimState("Idle")->setLoop(true);
            getAnimState("Idle")->setWeight(1);
        }
        else
        {
            mCurrentSpeed += dt;

            getAnimState("Idle")->setEnabled(false);
            getAnimState("Idle")->setLoop(true);
            getAnimState("Idle")->setWeight(0);
        }

        // Limit motion speed
        if (mCurrentSpeed > 1.0)
            mCurrentSpeed = 1.0;
        if (mCurrentSpeed < 0.0)
            mCurrentSpeed = 0.0;

    //    if(mCurrentSpeed == 0.0)
        if (onGround())
        {
            getAnimState("Jump")->setEnabled(false);
            getAnimState("Jump")->setWeight(0);

            getAnimState("Run")->setWeight(mCurrentSpeed);
            getAnimState("Walk")->setWeight(mCurrentSpeed);

            getAnimState("Idle")->setEnabled(true);
            getAnimState("Idle")->setWeight(1-mCurrentSpeed);
        }
        else
        {
        }

        Vector3 v = Vector3::UNIT_Z.getRotationTo(mDirection) * mTranslateVector;

        Vector3 u = mNode->getOrientation() * Vector3::UNIT_Z;
        Quaternion q = u.getRotationTo(mDirection);

        Real rotateSpeed = 3.0f;
        q = Quaternion::Slerp(rotateSpeed*dt, Quaternion::IDENTITY, q);
        mNode->rotate(q);

        //
        btVector3 walkDirection = BtOgre::Convert::toBullet(v);
        btScalar  walkVelocity = btScalar(1.1) * 40.0; // 4 km/h -> 1.1 m/s
        btScalar  walkSpeed = walkVelocity ;

        //
//        btScalar d = (u - mDirection).length();

        btTransform trans;
        mRigidBody->getMotionState()->getWorldTransform (trans);
        trans.setRotation (BtOgre::Convert::toBullet(mNode->getOrientation()));

        btVector3 linearVelocity = mRigidBody->getLinearVelocity();

        btScalar speed = linearVelocity.length();
        if (speed < maxLinearVelocity)
            mRigidBody->setLinearVelocity (linearVelocity + walkDirection*walkSpeed);

        mRigidBody->getMotionState()->setWorldTransform (trans);
        mRigidBody->setCenterOfMassTransform (trans);

*/


		return true;

    }


bool Character::frameEnded(const FrameEvent& evt)
{
return true;
}

bool Character::frameStarted(const FrameEvent& evt)
{
        // iterate ragbones
		RagDoll* rg = static_cast<RagDoll*>(mRagDoll);
		if(rg==NULL) return true;


//        for (RagDoll::RagBoneListIterator it = rg->mBones.begin(); it != rg->mBones.end(); it++)
//        {
//            Ogre::Vector3 pos;
//            Ogre::Quaternion orient;
//
//            RagDoll::RagBone* bone = (*it);
//            Bone* ogrebone = (*it)->getOgreBone();
//			ogrebone->setManuallyControlled(true);
//
//            Quaternion nodeorient = mNode->_getDerivedOrientation();
//            Quaternion boneorient = ogrebone->_getDerivedOrientation();
//            Vector3 bonepos = mNode->_getDerivedPosition() + nodeorient * ogrebone->_getDerivedPosition();
//
//            btTransform trans;
//            trans.setIdentity();
//            trans.setOrigin(BtOgre::Convert::toBullet(bonepos));
//            trans.setRotation(BtOgre::Convert::toBullet(nodeorient * boneorient));
//
//
//            bone->getBody()->setMotionState(new btDefaultMotionState(trans));
//		}

        for (RagDoll::RagBoneListIterator it = rg->mBones.begin(); it != rg->mBones.end(); it++)
        {
//            RagDoll::RagBone* bone = (*it);
            Bone* ogrebone = (*it)->getOgreBone();
			ogrebone->setManuallyControlled(true);

//			ogrebone->setOrientation(BtOgre::Convert::toOgre(bone->getBody()->getOrientation()));
//			ogrebone->setPosition(BtOgre::Convert::toOgre(bone->getBody()->getCenterOfMassPosition()));
		}
	return true;
}
